﻿using System;
using System.IO;
using System.IO.Packaging;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Globalization;
using System.Web;
using System.Web.Mvc;
using CSBackup_Web.Models;
using CSBackup_Web.Sources;
using CSBackup_Web.Sources.Override;
using CSBackup_Web.Sources.ui_Legacy;


namespace CSBackup_Web.Controllers
{
    [Authorize]
    public class HomeController : AsyncController
    {
        public static readonly string FOLDER = @"<文件夹>";
        public static readonly string NOEXT = @"<无后缀名文件>";

        [HttpGet]
        public ActionResult Index()
        {
            HomeModel m = new HomeModel();
            if (TempData["model"] != null)
            {
                m = (HomeModel)TempData["model"];
            }

            Log.LoadOldLogFile(m.LogInfo, m.ProjInfo);
            m.LogInfoFull = m.LogInfo;

            //Load file type drop down list
            #region
            List<string> fileList = new List<string>();
            for (int i = 0; i < m.ProjInfo.CurrentBackup.FileList.Count; i++)
                fileList.Add(Path.GetFileName(m.ProjInfo.CurrentBackup.FileList[i]));

            //Only do when need to do
            bool equals = true;
            if (fileList.Count != m.FileList.Count)
                equals = false;
            else
            {
                for (int i = 0; i < fileList.Count; i++)
                {
                    if (!fileList[i].Equals(m.FileList[i]))
                        equals = false;
                }
            }
            if (!equals)
            {
                m.TypeList.Clear();
                m.FileList.Clear();
                m.FileListValues.Clear();
                for (int i = 0; i < m.ProjInfo.CurrentBackup.FileList.Count; i++)
                {
                    string fullName = m.ProjInfo.CurrentBackup.FileList[i];
                    string extension = Path.GetExtension(fullName);
                    string name = Path.GetFileName(fullName);
                    m.FileList.Add(name);
                    m.FileListValues.Add(true);
                    if (extension == string.Empty)
                        extension = NOEXT;
                    if (!m.TypeList.Contains(extension))
                        m.TypeList.Add(extension);
                }
            }
            #endregion

            //Push info into session
            TempData["model"] = m;
            return View(m);
        }

        public ActionResult ClosePrj()
        {
            TempData["model"] = null;
            return RedirectToAction("Index", "Home");
        }

        [HttpPost]
        public async Task<ActionResult> BackupNow(HomeModel m, string homeSubmit)
        {
            if (TempData["model"] != null)
            {
                m = (HomeModel)TempData["model"];
            }

            switch (homeSubmit)
            {
                case "开始备份":
                    #region
                    {
                        if (!m.IsAuto)
                        {
                            //如果尚未执行过全备份，则必须先执行一次全备份才能执行其他类型备份
                            if (!m.BkpType.Equals("Full") && (0 == m.ProjInfo.FullBackupList.Count))
                            {
                                TempData["alert"] = "在执行其他类型备份之前必须先对所有文件执行一次全备份！";
                                return RedirectToAction("Index", "Home");
                            }
                            //如果是第一次执行全备份，要求所有文件都要全备份
                            if (m.BkpType.Equals("Full") && (0 == m.ProjInfo.FullBackupList.Count))
                            {
                                for (int num = 0; num < m.FileListValues.Count; num++)
                                {
                                    if (!m.FileListValues[num])
                                    {
                                        TempData["alert"] = "第一次执行全备份时必须备份所有文件！";
                                        return RedirectToAction("Index", "Home");
                                    }
                                }
                            }
                            bool chooseNothing = true;
                            for (int i = 0; i < m.FileListValues.Count; i++)
                            {
                                if (m.FileListValues[i])
                                    chooseNothing = false;
                            }
                            if (chooseNothing)
                                return View(m);
                            List<string> selected = new List<string>();
                            for (int i = 0; i < m.FileListValues.Count; i++)
                            {
                                if (m.FileListValues[i])
                                {
                                    selected.Add(m.ProjInfo.CurrentBackup.FileList[i]);
                                }
                            }

                            bool bkpResult = await backup(m.ProjInfo.BkpPrjFile, selected.ToArray(), selected.Count, m.BkpType, m.GrainType);
                            string bkpFile = m.ProjInfo.BkpPrjFile;
                            frmUI1.CleanUpPrj(m.ProjInfo);
                            ToolConfigFile.LoadPrjFromFile(m.ProjInfo, bkpFile);
                            if (bkpResult)
                            {
                                TempData["alert"] = "备份成功！";
                            }

                            TempData["model"] = m;
                            return RedirectToAction("Index", "Home");
                        }
                        else
                        {
                            TempData["model"] = new AutoBkpModel();
                            ((AutoBkpModel)TempData["model"]).ProjInfo = m.ProjInfo;
                            return RedirectToAction("AutoBkp", "Settings");
                        }
                    }
                    #endregion
                case "过滤":
                    #region
                    {
                        string chosenType;
                        if (m.ChosenType == NOEXT)
                            chosenType = string.Empty;
                        else
                            chosenType = m.ChosenType;
                        for (int i = 0; i < m.FileList.Count; i++)
                        {
                            if (Path.GetExtension(m.FileList[i]) == chosenType)
                                m.FileListValues[i] = true;
                            else
                                m.FileListValues[i] = false;
                        }

                        TempData["model"] = m;
                        return RedirectToAction("Index");
                    }
                    #endregion
            }
            return RedirectToAction("Index");
        }
        private async Task<bool> backup(string location, string[] selected, int count, string type, string grainType)
        {
            return BackupExport.BackUp(location, selected, count, type, null, grainType);
        }

        /// <summary>
        /// 此函数能正确执行的前提是，无论是原来C++代码产生的日志，
        /// 还是以后新写的日志模块产生的日志，每一条日志记录的前
        /// “10”个字符记录的都是日期，且格式是“yyyy-MM-dd”
        /// </summary>
        [HttpPost]
        public ActionResult RefreshLog(HomeModel m)
        {
            if (TempData["model"] != null)
            {
                ((HomeModel)TempData["model"]).LogStart = m.LogStart;
                ((HomeModel)TempData["model"]).LogEnd = m.LogEnd;
                m = (HomeModel)TempData["model"];
                m.ActiveTab = 2;
            }

            if (ModelState.IsValid)
            {
                DateTime logStart = DateTime.ParseExact(m.LogStart, "d", CultureInfo.InvariantCulture);
                DateTime logEnd = DateTime.ParseExact(m.LogEnd, "d", CultureInfo.InvariantCulture);

                int ret = 0;
                string start = string.Empty;
                string end = string.Empty;
                string format = @"yyyy-MM-dd";

                m.LogInfo.Clear();

                start = logStart.ToString(format);
                end = logEnd.ToString(format);
                ret = String.Compare(start, end);
                if (ret > 0)
                {
                    TempData["alert"] = "起始日期不能超过结束日期！";
                    TempData["model"] = m;
                    return RedirectToAction("Index");
                }

                for (int i = 0; i < m.LogInfoFull.Count; i++)
                {
                    ret = String.Compare(m.LogInfoFull[i][0], start);
                    if (ret < 0)
                        continue;
                    ret = String.Compare(m.LogInfoFull[i][0], end);
                    if (ret > 0)
                        continue;
                    m.LogInfo.Add(m.LogInfoFull[i]);
                }
            }

            TempData["model"] = m;
            return RedirectToAction("Index");
        }

        [HttpPost]
        public ActionResult ListTypeConfirm(HomeModel m)
        {
            //Pull info from session
            #region
            if (TempData["model"] != null)
            {
                ((HomeModel)TempData["model"]).BkpListType = m.BkpListType;
                m = (HomeModel)TempData["model"];
            }
            m.ActiveTab = 1;
            #endregion

            m.BkpList.Clear();

            m.ProjInfo.SelectedBackup = null;
            List<BackupInfo> list = null;
            ToolBackupInfo.LoadFullBkpInfoList(m.ProjInfo.FullBkpPath, m.ProjInfo.FullBackupList);
            ToolBackupInfo.LoadIncBkpInfoList(m.ProjInfo.IncBkpPath, m.ProjInfo.IncBackupList);
            ToolBackupInfo.LoadDiffBkpInfoList(m.ProjInfo.DiffBkpPath, m.ProjInfo.DiffBackupList);
            ToolBackupInfo.LoadDiffIncBkpInfoList(m.ProjInfo.DiffIncBkpPath, m.ProjInfo.DiffIncBackupList);
            switch (m.BkpListType)
            {
                case "full":
                    list = m.ProjInfo.FullBackupList;
                    break;
                case "inc":
                    list = m.ProjInfo.IncBackupList;
                    break;
                case "diff":
                    list = m.ProjInfo.DiffBackupList;
                    break;
                default:
                    list = m.ProjInfo.DiffIncBackupList;
                    break;
            }
            foreach (BackupInfo bkpInfo in list)
            {
                m.BkpList.Add(bkpInfo.BkpName);
            }

            //Push info to session
            TempData["model"] = m;
            return RedirectToAction("Index");
        }

        [HttpPost]
        public ActionResult ListConfirm(HomeModel m)
        {
            if (m.BkpListSelected == -1)
            {
                TempData["alert"] = "请先选择一个备份列表";
                return RedirectToAction("Index");
            }

            //Pull info from session
            if (TempData["model"] != null)
            {
                ((HomeModel)TempData["model"]).BkpListSelected = m.BkpListSelected;
                m = (HomeModel)TempData["model"];
            }
            m.ActiveTab = 1;

            List<BackupInfo> list = null;
            switch (m.BkpListType)
            {
                case "full":
                    list = m.ProjInfo.FullBackupList;
                    break;
                case "inc":
                    list = m.ProjInfo.IncBackupList;
                    break;
                case "diff":
                    list = m.ProjInfo.DiffBackupList;
                    break;
                default:
                    list = m.ProjInfo.DiffIncBackupList;
                    break;
            }
            string pos = string.Empty;
            BackupInfo bkpInfo = list[m.BkpListSelected];
            m.ProjInfo.SelectedBackup = bkpInfo;
            m.BkpWay = bkpInfo.BkpType;
            m.BkpTime = bkpInfo.BkpTime;
            m.BkpSize = bkpInfo.BkpFileSize;
            m.BkpCnt = bkpInfo.BkpFileAmount;
            m.BkpDpnd = bkpInfo.BkpDepended;

            //Push info to session
            TempData["model"] = m;
            return RedirectToAction("Index");
        }

        [HttpGet]
        public async Task<ActionResult> RcvrAllClicked()
        {
            //Pull info from session
            HomeModel m = new HomeModel();
            if (TempData["model"] != null)
            {
                TempData["model"] = new HomeModel();
                m = (HomeModel)TempData["model"];
            }
            m.ActiveTab = 1;

            if (null == m.ProjInfo.SelectedBackup)
            {
                TempData["alert"] = "请先选择一个要还原的备份！";
                TempData["model"] = m;
                return RedirectToAction("Index");
            }

            // Clean the directory
            string recoveryPath = Path.Combine(m.ProjInfo.PrjLocation, "Recover");
            if (Directory.Exists(recoveryPath))
            {
                foreach (string file in Directory.GetFiles(recoveryPath))
                {
                    System.IO.File.Delete(file);
                }
                foreach (string dir in Directory.GetDirectories(recoveryPath))
                {
                    Directory.Delete(dir, true);
                }
            }

            try
            {
                BackupInfo backupinfo = m.ProjInfo.SelectedBackup;
                int rcvResult;
                if (backupinfo != null && m.ProjInfo != null)
                    rcvResult = await RcvrAll(m.ProjInfo.BkpPrjFile, backupinfo);
            }
            catch (Exception exception)
            {
                TempData["alert"] = exception.Message;
                TempData["model"] = m;
                return RedirectToAction("Index");
            }

            // Collect files and zip them for downloading
            string zipLocation = Path.Combine(recoveryPath, "recovery.zip");
            foreach (string file in Directory.GetFiles(recoveryPath))
            {
                Common.AddFileToZip(zipLocation, file);
            }
            Response.ContentType = "application/zip";
            Response.AppendHeader("Content-Disposition", "attachment; filename=Recovery.zip");
            Response.TransmitFile(zipLocation);
            Response.End();

            TempData["model"] = m;
            return RedirectToAction("Index");
        }
        private async Task<int> RcvrAll(string projPath, BackupInfo backupInfo)
        {
            BackupRecovery.RecoveryWholeRecoveryPoint(projPath, backupInfo);
            return 1;
        }

        public ActionResult HomeSelectAll()
        {
            if (TempData["model"] != null)
            {
                HomeModel m = (HomeModel)TempData["model"];
                for (int i = 0; i < m.FileListValues.Count; i++)
                {
                    m.FileListValues[i] = true;
                }
                TempData["model"] = m;
            }
            return RedirectToAction("Index");
        }
        public ActionResult HomeCancelAll()
        {
            if (TempData["model"] != null)
            {
                HomeModel m = (HomeModel)TempData["model"];
                for (int i = 0; i < m.FileListValues.Count; i++)
                {
                    m.FileListValues[i] = false;
                }
                TempData["model"] = m;
            }
            return RedirectToAction("Index");
        }

        [HttpGet]
        public async Task<ActionResult> BtnDelAll()
        {
            HomeModel m = new HomeModel();
            if (TempData["model"] != null)
            {
                m = ((HomeModel)TempData["model"]);
            }
            m.ActiveTab = 1;

            if (null == m.ProjInfo.SelectedBackup)
            {
                TempData["alert"] = "您还没有选择一个还原点，请先选择。";
                TempData["model"] = m;
                return RedirectToAction("Index");
            }

            int del = await btnDelAll(m.ProjInfo.PrjLocation, m.ProjInfo.SelectedBackup.BkpLocation, m.ProjInfo.SelectedBackup.BkpName);

            if (del > 0)
            {
                TempData["alert"] = "删除整个还原点成功！";
            }
            else
            {
                TempData["alert"] = "发生未知错误，删除还原点失败！";
            }
            TempData["model"] = m;
            return RedirectToAction("Index");
        }
        private async Task<int> btnDelAll(string location, string path, string name)
        {
            return BackupRecovery.DelRecoveryPoint(location, path, name);
        }

        [HttpGet]
        public ActionResult BtnSSSync()
        {
            HomeModel m = new HomeModel();
            if (TempData["model"] != null)
            {
                m = (HomeModel)TempData["model"];
            }
            m.ActiveTab = 1;
            int ret = 0;
            ret = BackupRecovery.SyncSelfSep(m.ProjInfo.BkpPrjFile);
            if (ret != 0)
            {
                TempData["alert"] = "自分离模式同步完成！";
            }
            else
            {
                TempData["alert"] = "发生未知错误，自分离同步失败！";
            }
            TempData["model"] = m;
            return RedirectToAction("Index");
        }

        public ActionResult PrtRcvrClicked(HomeModel m)
        {
            //Pull info from session
            if (TempData["model"] != null)
            {
                m = (HomeModel)TempData["model"];
            }

            PrtRcvrModel targetModel = new PrtRcvrModel();

            if (null == m.ProjInfo.SelectedBackup)
            {
                TempData["alert"] = "请先选择一个要还原的备份！";
                TempData["model"] = m;
                return RedirectToAction("Index");
            }
            if ((BackupInfo.BACKUP_TYPE_INC == m.ProjInfo.SelectedBackup.BkpType) || (BackupInfo.BACKUP_TYPE_DIFINC == m.ProjInfo.SelectedBackup.BkpType))
            {
                TempData["alert"] = "和增量有关的备份不支持部分文件恢复，因为文件在多个版本里可能有较多新增和删除！";
                TempData["model"] = m;
                return RedirectToAction("Index");
            }

            //填充文件列表
            int ret = 0;

            //这个窗口必须在curPrj.selectedBackup != null时才能打开，故不用检查
            m.ProjInfo.SelectedFileList.Clear();
            m.ProjInfo.SelectedDirList.Clear();

            ret = frmPrtRcvr.LoadAllBkpedFiles(m.ProjInfo);
            if (ret != 0)
            {
                TempData["alert"] = "in RefreshList(): ret = " + ret.ToString();
                TempData["model"] = m;
                return RedirectToAction("Index", "Home");
            }

            //selectedFileList里在装载时就保证了没有重复的元素
            ret = m.ProjInfo.SelectedFileList.Count;
            FileDetail file = null;
            for (int i = 0; i < ret; ++i)
            {
                file = m.ProjInfo.SelectedFileList[i];
                List<string> item = new List<string>();
                item.Add(file.ToString());
                item.Add(file.CreationTime.Date.ToString("yyyy-MM-dd"));
                item.Add(file.Size.ToString());
                targetModel.FileInfo.Add(item);
                targetModel.FileInfoValue.Add(false);
            }

            TempData["model"] = targetModel;
            return RedirectToAction("PrtRcvr", "Settings");
        }

        public ActionResult ChooseProjectClicked()
        {
            HomeModel m = new HomeModel();
            if (TempData["model"] != null)
            {
                m = (HomeModel)TempData["model"];
            }
            ChoosePrjModel targetModel = new ChoosePrjModel();

            targetModel.ProjInfo = m.ProjInfo;
            targetModel.ActiveTab = m.ActiveTab;
            string rootPath = Path.Combine(Server.MapPath("~/App_Data"), User.Identity.Name);
            DirectoryInfo rootDir = new DirectoryInfo(rootPath);
            foreach (DirectoryInfo dir in rootDir.GetDirectories())
            {
                targetModel.PrjNames.Add(dir.Name);
            }

            TempData["model"] = targetModel;
            return RedirectToAction("ChoosePrj", "Settings");
        }

        public ActionResult NewProjectClicked()
        {
            HomeModel m = new HomeModel();
            if (TempData["model"] != null)
            {
                m = (HomeModel)TempData["model"];
            }
            NewPrjNameModel targetModel = new NewPrjNameModel();

            targetModel.ActiveTab = m.ActiveTab;
            targetModel.ProjInfo = m.ProjInfo;

            TempData["model"] = targetModel;
            return RedirectToAction("NewPrjName", "Settings");
        }
    }
}
